<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildThisFileDirectory)\hc\localization.target" />

  <PropertyGroup>
    <Configuration>Release</Configuration>
    <!-- Version components  -->
    <Major Condition="$(PROGRAM_VERSION.Split('.').Length) != 3 ">1</Major>
    <Minor Condition="$(PROGRAM_VERSION.Split('.').Length) != 3 ">0</Minor>
    <Build Condition="$(PROGRAM_VERSION.Split('.').Length) != 3 ">0</Build>
    
    <Major Condition="$(PROGRAM_VERSION.Split('.').Length) == 3 ">$(PROGRAM_VERSION.Split('.')[0])</Major>
    <Minor Condition="$(PROGRAM_VERSION.Split('.').Length) == 3 ">$(PROGRAM_VERSION.Split('.')[1])</Minor>
    <Build Condition="$(PROGRAM_VERSION.Split('.').Length) == 3 ">$(PROGRAM_VERSION.Split('.')[2])</Build>

    <Revision Condition=" '$(Revision)' == '' ">0</Revision>
    <MultiProcessorCompilation>true</MultiProcessorCompilation>

    <!-- NSIS installer's path  -->
    <NSISPath>$(NSIS_ROOT)</NSISPath>

    <!-- binplace utility path  -->
    <BinPlacePath>$(WINDDK)\bin\x86</BinPlacePath>
    <SymStorePath>$(WINDDK)\Debuggers\x64</SymStorePath>
    <TmpFile>tmp.bat</TmpFile>
    <PgoEnabled>true</PgoEnabled>
    <GnuBasePath>$(ChocolateyInstall)\lib\winflexbison3\tools</GnuBasePath>
    <EchoCommand>echo</EchoCommand>
    <VsBasePath>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326</VsBasePath>
    <PvsStudioPath>c:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe</PvsStudioPath>
    <PvsStudioReportFile>linq2hash.plog</PvsStudioReportFile>
    <PlogConverterPath>c:\Program Files (x86)\PVS-Studio\PlogConverter.exe</PlogConverterPath>
  </PropertyGroup>
  <PropertyGroup Condition="$(KeyFile) != '' AND $(CertPassword) != '' AND $(SignTool) != ''">
    <SignCommand>"$(SignTool)" sign /f "$(KeyFile)" /p $(CertPassword) /t http://timestamp.verisign.com/scripts/timestamp.dll /v /d "hc" /du https://github.com/aegoroff/hc %251</SignCommand>
  </PropertyGroup>
  <PropertyGroup Condition="$(Configuration) == 'Release' AND $(PgoEnabled) == true">
    <LinkType>LinkType=PGInstrument</LinkType>
  </PropertyGroup>
  <PropertyGroup Condition="$(Configuration) == 'Debug'">
    <LinkType></LinkType>
  </PropertyGroup>
  <ItemGroup>
    <ResourceFile Include="$(MSBuildProjectDirectory)\hc\hc.rc" />
    <ResourceFile Include="$(MSBuildProjectDirectory)\l2h\l2h.rc" />
  </ItemGroup>
  <ItemGroup>
    <TargetverFile Include="$(MSBuildProjectDirectory)\hc\targetver.h" />
    <TargetverFile Include="$(MSBuildProjectDirectory)\l2h\targetver.h" />
  </ItemGroup>
  <!-- Update version -->
  <Target Name="VersionUpdater">
      <ItemGroup>
      <ResourceFiles Include="@(ResourceFile)">
        <Find><![CDATA[VALUE\s*"(FileVersion|ProductVersion)",\s*"\d+([.,]\s*)\d+([.,]\s*)\d+([.,]\s*)\d+"]]></Find>
        <ReplaceWith><![CDATA[VALUE "$1", "$(Major), $(Minor), $(Build), $(Revision)"]]></ReplaceWith>
        <Options>Singleline</Options>
      </ResourceFiles>
      <ResourceFiles Include="@(ResourceFile)">
        <Find><![CDATA[(FILEVERSION|PRODUCTVERSION)(\s*)(\d+),(\d+),(\d+),(\d+)]]></Find>
        <ReplaceWith><![CDATA[$1 $(Major),$(Minor),$(Build),$(Revision)]]></ReplaceWith>
        <Options>Singleline</Options>
      </ResourceFiles>
      <ResourceFiles Include="@(TargetverFile)">
        <Find><![CDATA[(#define PRODUCT_VERSION)(\s*)"(\d+).(\d+).(\d+).(\d+)"]]></Find>
        <ReplaceWith><![CDATA[$1 "$(Major).$(Minor).$(Build).$(Revision)"]]></ReplaceWith>
        <Options>Singleline</Options>
      </ResourceFiles>
    </ItemGroup>
    <RegexTransform Items="@(ResourceFiles)" />
  </Target>
    <ItemGroup>
        <Platform Include="x64" />
    </ItemGroup>
    <ItemGroup>
        <Arch Include="x64" />
    </ItemGroup>
  <!-- Compilation -->
  <Target Name="Compile" DependsOnTargets="VersionUpdater">
    <ItemGroup>
      <TestsProject Include="$(MSBuildProjectDirectory)\_tst.net\_tst.net.csproj" />
      <TestsProject Include="$(MSBuildProjectDirectory)\_tst.pgo\_tst.pgo.csproj" />
    </ItemGroup>
    <ItemGroup>
      <PgoProject Include="$(MSBuildProjectDirectory)\pcre\pcre.vcxproj" />
      <PgoProject Include="$(MSBuildProjectDirectory)\libtomcrypt\libtomcrypt.vcxproj" />
      <PgoProject Include="$(MSBuildProjectDirectory)\hc\hc.vcxproj" />
      <PgoProject Include="$(MSBuildProjectDirectory)\l2h\l2h.vcxproj" />
      <PgoProject Include="$(MSBuildProjectDirectory)\_tst\_tst.vcxproj" />
    </ItemGroup>
    <ItemGroup>
      <WorkingDir64 Include="$(MSBuildProjectDirectory)\x64\$(Configuration)" />
    </ItemGroup>
      <Exec Command='dotnet restore'/>
      <Exec
        Condition="$(GITHUB_REF) != ''"
        WorkingDirectory="$(MSBuildProjectDirectory)\l2h"
        ConsoleToMSBuild="True"
        Command='"$(GnuBasePath)\win_flex.exe" --wincompat --outfile="l2h.flex.c" l2h.lex'>
            <Output TaskParameter="ConsoleOutput" PropertyName="FlexOutput" />
      </Exec>
      <Message Text="$(FlexOutput)" Importance="Normal" />
      <Exec
        Condition="$(GITHUB_REF) != ''"
        WorkingDirectory="$(MSBuildProjectDirectory)\l2h"
        ConsoleToMSBuild="True"
        Command='"$(GnuBasePath)\win_bison.exe" --output="l2h.tab.c" -dy l2h.y'>
          <Output TaskParameter="ConsoleOutput" PropertyName="BisonOutput" />
      </Exec>
      <Message Text="$(BisonOutput)" Importance="Normal" />

    <MSBuild
      Projects="@(TestsProject)"
      BuildInParallel="true"
      Properties="Configuration=$(Configuration);Platform=AnyCPU" />
    <MSBuild
      Projects="@(PgoProject)"
      BuildInParallel="true"
      Properties="Configuration=$(Configuration);Platform=%(Platform.Identity);SolutionDir=$(MSBuildProjectDirectory)\;$(LinkType);MultiProcessorCompilation=$(MultiProcessorCompilation)" />
    <!-- HACK! -->
    <Copy
      SourceFiles="$(VsBasePath)\bin\HostX64\x64\pgort140.dll"
      DestinationFolder="%(WorkingDir64.Identity)"
      Condition="$(Configuration) == 'Release' AND $(PgoEnabled) == true" />

    <ItemGroup>
      <Profile Include="%(WorkingDir64.Identity)\*.pgc" />
    </ItemGroup>


    <Delete
      Condition="$(Configuration) == 'Release' AND $(PgoEnabled) == true"
      Files="@(Profile)" />

    <!-- PGO tests -->
    <Exec
        Command='dotnet test $(MSBuildProjectDirectory)\_tst.pgo\bin\$(Configuration)\_tst.pgo.dll -a "$(UserProfile)\.nuget\packages\xunit.runner.visualstudio\2.4.3\build\netcoreapp2.1"'
        Condition="$(Configuration) == 'Release' AND $(PgoEnabled) == true"/>

    <MSBuild
      Projects="@(PgoProject)"
      BuildInParallel="true"
      Condition="$(Configuration) == 'Release' AND $(PgoEnabled) == true"
      Properties="Configuration=$(Configuration);Platform=%(Platform.Identity);SolutionDir=$(MSBuildProjectDirectory)\;LinkType=PGOptimization;MultiProcessorCompilation=$(MultiProcessorCompilation)" />

  </Target>
  <!-- Native tests -->
  <Target Name="Tests" DependsOnTargets="Compile">
      <ItemGroup>
          <TestExe Include="$(MSBuildProjectDirectory)\x64\$(Configuration)\_t*.exe" />
      </ItemGroup>

      <Exec
          Command="%(TestExe.Identity) --gtest_output=xml:%(TestExe.RootDir)%(TestExe.Directory)"
          IgnoreStandardErrorWarningFormat="true"
          IgnoreExitCode="true"
          Timeout="30000">
          <Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
      </Exec>
      <Message Importance="high" Text="$(ErrorCode)"/>
  </Target>
  <!-- Managed tests -->
  <Target Name="ManagedTests" DependsOnTargets="Tests">
      <Exec Command='dotnet test $(MSBuildProjectDirectory)\_tst.net\bin\$(Configuration)\_tst.net.dll -a "$(UserProfile)\.nuget\packages\xunit.runner.visualstudio\2.4.3\build\netcoreapp2.1"'/>
  </Target>
  <ItemGroup>
    <Binfile Include="hc" />
    <Binfile Include="l2h" />
  </ItemGroup>
  <!-- Validation using PVS Studio -->
  <Target Name="PvsStudioValidation" DependsOnTargets="Compile">
    <ItemGroup>
      <ReportFormat Include="Html" />
      <ReportFormat Include="Txt" />
    </ItemGroup>
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)"
      Condition="$(TEAMCITY_VERSION) != ''"
      IgnoreExitCode="True"
      Command='"$(PvsStudioPath)" -t "$(MSBuildProjectDirectory)\linq2hash.sln" -o "$(MSBuildProjectDirectory)\$(PvsStudioReportFile)" -p x64 -s "$(MSBuildProjectDirectory)\PVSSettings.xml"' />
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)"
      Condition="$(TEAMCITY_VERSION) != ''"
      Command='"$(PlogConverterPath)" -t %(ReportFormat.Identity) "$(MSBuildProjectDirectory)\$(PvsStudioReportFile)" -a GA:1,2;64:1;OP:1,2 -s "$(MSBuildProjectDirectory)\PVSSettings.xml"' />
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)"
      Condition="$(TEAMCITY_VERSION) != ''"
      Command='"$(PlogConverterPath)" -t Totals "$(MSBuildProjectDirectory)\$(PvsStudioReportFile)" -s "$(MSBuildProjectDirectory)\PVSSettings.xml"' />
  </Target>
  <!-- Binplace tasks -->
  <Target Name="Binplace" DependsOnTargets="ManagedTests;PvsStudioValidation">
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)\x64\$(Configuration)"
      Condition="$(GITHUB_REF) != ''"
      Command='"$(BinPlacePath)\binplace.exe" -v -p $(MSBuildProjectDirectory)\..\binplace.txt -r $(MSBuildProjectDirectory)\Binplace-x64\$(Configuration) %(Binfile.Identity).exe' />
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)"
      Condition="$(GITHUB_REF) != ''"
      Command='"$(SymStorePath)\symstore.exe" add /F $(MSBuildProjectDirectory)\Binplace-x64\$(Configuration)\%(Binfile.Identity).pdb /S "$(_NTAMD64TREE)\sym.pri" /t "%(Binfile.Identity) calculator" /r /z pri' />
  </Target>
  <!-- Sign executables -->
  <Target Name="ExeSigning" DependsOnTargets="Binplace">

    <ItemGroup>
      <TargetPathToCreate Include="$(MSBuildProjectDirectory)\Binplace-x64\$(Configuration)" />
    </ItemGroup>

    <MakeDir
      Directories="@(TargetPathToCreate)"/>

    <ItemGroup>
      <x64bin Include="$(MSBuildProjectDirectory)\x64\$(Configuration)\*.exe" />
    </ItemGroup>

    <Copy
      SourceFiles="@(x64bin)"
      DestinationFolder="$(MSBuildProjectDirectory)\Binplace-x64\$(Configuration)" />

    <WriteLinesToFile Condition="$(SignCommand) != ''" File="$(TmpFile)" Lines="$(SignCommand)" />

    <Exec
      Condition="$(SignCommand) != ''"
      Command="$(TmpFile) &quot;$(MSBuildProjectDirectory)\Binplace-x64\$(Configuration)\%(Binfile.Identity).exe&quot; > NUL 2>&amp;1"
      WorkingDirectory="$(MsBuildThisFileDirectory)" />
    <Delete Files="$(TmpFile)" Condition="Exists('$(TmpFile)')" />
  </Target>
  <ItemGroup>
    <Installer Include="mainHLINQ.nsi" />
  </ItemGroup>
  <!-- Setup building -->
  <Target Name="Setup" DependsOnTargets="ExeSigning;LocalizationBuild">
    <MakeDir Directories="$(MSBuildProjectDirectory)\Install\$(Configuration)" />

    <!-- Documentation building -->
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)\..\docs"
      Command='handlebars-cli Readme.hc.en.st "{""langName"": ""Hash Calculator"", ""appName"": ""hc""}" > Readme.hc.en.txt' />
    <Exec
      WorkingDirectory="$(MSBuildProjectDirectory)\..\docs"
      Command='handlebars-cli Readme.hc.ru.st "{""langName"": ""Хэш калькулятор"", ""appName"": ""hc""}" > Readme.hc.ru.txt' />
    <WriteLinesToFile Condition="$(SignCommand) != ''" File="$(TmpFile)" Lines="$(SignCommand)" />
    <WriteLinesToFile Condition="$(SignCommand) == ''" File="$(TmpFile)" Lines="$(EchoCommand)" />
      <Exec
        WorkingDirectory="$(MSBuildProjectDirectory)\Install"
        Command='"$(NSISPath)\makensis.exe" /NOTIFYHWND 131948 /DConfiguration=$(Configuration) /DPRODUCT_VERSION=$(Major).$(Minor).$(Build).$(Revision) /DCodeSigner="$(MSBuildProjectDirectory)\$(TmpFile)" "%(Installer.Identity)"'>
      </Exec>

    <ItemGroup>
      <SetupFile Include="$(MSBuildProjectDirectory)\Install\$(Configuration)\*.exe" />
    </ItemGroup>

    <Exec
      Condition="$(SignCommand) != ''"
      Command="$(TmpFile) &quot;%(SetupFile.Identity)&quot; > NUL 2>&amp;1"
      WorkingDirectory="$(MsBuildThisFileDirectory)" />
    <Move
      SourceFiles="@(SetupFile->'%(FullPath)')"
      Condition="$(Configuration) == 'Debug'"
      OverwriteReadOnlyFiles="true"
      DestinationFiles="@(SetupFile-&gt;'%(RootDir)%(Directory)$([System.String]::Concat('%(FileName)','-dev'))%(Extension)')" />
    <Delete Files="$(TmpFile)" Condition="Exists('$(TmpFile)')" />
  </Target>
  <!-- Main target -->
  <Target Name="Build" DependsOnTargets="Setup">
    <Message Text="Build $(Major).$(Minor).$(Build).$(Revision) Complete" />
  </Target>

  <UsingTask TaskName="RegexTransform" TaskFactory="CodeTaskFactory"
             AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <Items ParameterType="Microsoft.Build.Framework.ITaskItem[]" />
    </ParameterGroup>
    <Task>
      <Using Namespace="System.IO" />
      <Using Namespace="System.Text.RegularExpressions" />
      <Using Namespace="Microsoft.Build.Framework" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
			   foreach(var item in Items)
			   {
				 string fileName = item.GetMetadata("FullPath");
				 string find = item.GetMetadata("Find");
				 string replaceWith = item.GetMetadata("ReplaceWith");
				 string optionsValue = item.GetMetadata("Options") ?? "";
		 
				 var options = string.IsNullOrWhiteSpace(optionsValue) ?
					 RegexOptions.None : (RegexOptions)Enum.Parse(typeof(RegexOptions), optionsValue.Replace('|', ','));
		 
				 if(!File.Exists(fileName))
				 {
				   Log.LogError("Could not find file: {0}", fileName);
				   return false;
				 }
				 string content = File.ReadAllText(fileName);
				 File.WriteAllText(
				   fileName,
				   Regex.Replace(
					 content,
					 find,
					 replaceWith,
					 options
				   )
				 );
			   }
			 ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>